package com.chindeo.repository.util;

import android.os.SystemClock;

import com.chindeo.repository.data.livedata.DeviceInfoLiveData;

import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.UUID;

public class UUIDGenerator {


    private static final char[] hexArray = "0123456789ABCDEF".toCharArray();


    /**
     * Type 3 UUID Generation
     *
     * @throws UnsupportedEncodingException
     */
    public static UUID generateType3UUID(String name) throws UnsupportedEncodingException {
        byte[] nameSpaceBytes = bytesFromUUID("6ba7b810-9dad-11d1-80b4-00c04fd430c9");
        byte[] nameBytes = name.getBytes("UTF-8");
        byte[] result = joinBytes(nameSpaceBytes, nameBytes);

        return  UUID.nameUUIDFromBytes(result);
    }


    //return (uuid(uuid(key+time)+time))
    public static UUID getChindeoUUIDv3(String key) throws UnsupportedEncodingException {
        String uuid = generateType3UUID(key).toString();
        return generateType3UUID(uuid+ System.currentTimeMillis());
    }

//    /**
//     * Type 4 UUID Generation
//     */
//    public static UUID generateType4UUID() {
//        UUID uuid = UUID.randomUUID();
//        return uuid;
//    }
//
//    /**
//     * Type 5 UUID Generation
//     *
//     * @throws UnsupportedEncodingException
//     */
//    public static UUID generateType5UUID(String namespace, String name) throws UnsupportedEncodingException {
//
//        byte[] nameSpaceBytes = bytesFromUUID(namespace);
//        byte[] nameBytes = name.getBytes("UTF-8");
//        byte[] result = joinBytes(nameSpaceBytes, nameBytes);
//
//        return type5UUIDFromBytes(result);
//    }
//
//    public static UUID type5UUIDFromBytes(byte[] name) {
//        MessageDigest md;
//        try {
//            md = MessageDigest.getInstance("SHA-1");
//        } catch (NoSuchAlgorithmException nsae) {
//            throw new InternalError("SHA-1 not supported", nsae);
//        }
//        byte[] bytes = Arrays.copyOfRange(md.digest(name), 0, 16);
//        bytes[6] &= 0x0f; /* clear version        */
//        bytes[6] |= 0x50; /* set to version 5     */
//        bytes[8] &= 0x3f; /* clear variant        */
//        bytes[8] |= 0x80; /* set to IETF variant  */
//        return constructType5UUID(bytes);
//    }
//
//    private static UUID constructType5UUID(byte[] data) {
//        long msb = 0;
//        long lsb = 0;
//        assert data.length == 16 : "data must be 16 bytes in length";
//
//        for (int i = 0; i < 8; i++)
//            msb = (msb << 8) | (data[i] & 0xff);
//
//        for (int i = 8; i < 16; i++)
//            lsb = (lsb << 8) | (data[i] & 0xff);
//        return new UUID(msb, lsb);
//    }

    /**
     * Unique Keys Generation Using Message Digest and Type 4 UUID
     *
     * @throws NoSuchAlgorithmException
     * @throws UnsupportedEncodingException
     */
    public static String generateUniqueKeysWithUUIDAndMessageDigest() throws NoSuchAlgorithmException, UnsupportedEncodingException {
        MessageDigest salt = MessageDigest.getInstance("SHA-256");
        salt.update(UUID.randomUUID()
                .toString()
                .getBytes("UTF-8"));
        String digest = bytesToHex(salt.digest());
        return digest;
    }

    private static String bytesToHex(byte[] bytes) {
        char[] hexChars = new char[bytes.length * 2];
        for (int j = 0; j < bytes.length; j++) {
            int v = bytes[j] & 0xFF;
            hexChars[j * 2] = hexArray[v >>> 4];
            hexChars[j * 2 + 1] = hexArray[v & 0x0F];
        }
        return new String(hexChars);
    }

    private static byte[] bytesFromUUID(String uuidHexString) {
        String normalizedUUIDHexString = uuidHexString.replace("-", "");

        assert normalizedUUIDHexString.length() == 32;

        byte[] bytes = new byte[16];
        for (int i = 0; i < 16; i++) {
            byte b = hexToByte(normalizedUUIDHexString.substring(i * 2, i * 2 + 2));
            bytes[i] = b;
        }
        return bytes;
    }

    public static byte hexToByte(String hexString) {
        int firstDigit = Character.digit(hexString.charAt(0), 16);
        int secondDigit = Character.digit(hexString.charAt(1), 16);
        return (byte) ((firstDigit << 4) + secondDigit);
    }

    public static byte[] joinBytes(byte[] byteArray1, byte[] byteArray2) {
        int finalLength = byteArray1.length + byteArray2.length;
        byte[] result = new byte[finalLength];

        for (int i = 0; i < byteArray1.length; i++) {
            result[i] = byteArray1[i];
        }

        for (int i = 0; i < byteArray2.length; i++) {
            result[byteArray1.length + i] = byteArray2[i];
        }

        return result;
    }

    public static UUID generateType5UUID(String name) {

        try {

            byte[] bytes = name.getBytes(StandardCharsets.UTF_8);
            MessageDigest md = MessageDigest.getInstance("SHA-1");

            byte[] hash = md.digest(bytes);

            long msb = getLeastAndMostSignificantBitsVersion5(hash, 0);
            long lsb = getLeastAndMostSignificantBitsVersion5(hash, 8);
            // Set the version field
            msb &= ~(0xfL << 12);
            msb |= ((long) 5) << 12;
            // Set the variant field to 2
            lsb &= ~(0x3L << 62);
            lsb |= 2L << 62;
            return new UUID(msb, lsb);

        } catch (NoSuchAlgorithmException e) {
            throw new AssertionError(e);
        }
    }

    private static long getLeastAndMostSignificantBitsVersion5(final byte[] src, final int offset) {
        long ans = 0;
        for (int i = offset + 7; i >= offset; i -= 1) {
            ans <<= 8;
            ans |= src[i] & 0xffL;
        }
        return ans;
    }


}
